import ctypes
from win32api import ShellExecute
import win32con, win32process, win32event
from typing import List
import time, sys, psutil
from datetime import datetime
import logging

DEFAULT_DELAY_TIME = 3

logging.basicConfig(filename="log.txt", filemode="a", encoding="utf-8")
log = logging.getLogger("main")


def is_ac_power() -> bool:
    """
    检查是否连接了AC供电
    """
    from ctypes import wintypes

    class SYSTEM_POWER_STATUS(ctypes.Structure):
        _fields_ = [
            ("ACLineStatus", wintypes.BYTE),
            ("BatteryFlag", wintypes.BYTE),
            ("BatteryLifePercent", wintypes.BYTE),
            ("Reserved1", wintypes.BYTE),
            ("BatteryLifeTime", wintypes.DWORD),
            ("BatteryFullLifeTime", wintypes.DWORD),
        ]

    SYSTEM_POWER_STATUS_P = ctypes.POINTER(SYSTEM_POWER_STATUS)

    GetSystemPowerStatus = ctypes.windll.kernel32.GetSystemPowerStatus
    GetSystemPowerStatus.argtypes = [SYSTEM_POWER_STATUS_P]
    GetSystemPowerStatus.restype = wintypes.BOOL

    status = SYSTEM_POWER_STATUS()
    if not GetSystemPowerStatus(ctypes.pointer(status)):
        raise ctypes.WinError()

    return status.ACLineStatus


def _runtask_by_shellexecute(exe, parament, work_dir):
    exeinfo = f"run:\t{exe} {parament}"
    print(exeinfo)
    try:
        ShellExecute(None, "open", exe, parament, work_dir, 0)
    except Exception as e:
        _log_err(f"failed {exeinfo}.\t{e}")
    # nCmdShow：0为隐藏窗口，7为最小化窗口，1为正常显示


def _runtask_by_createprocess(exe, parament, work_dir):
    cmd_line = f'"{exe}" {parament}'
    print("run", cmd_line)

    # Set creation flags to create the process detached from the parent process
    creation_flags = win32con.DETACHED_PROCESS | win32con.CREATE_NO_WINDOW
    startup_info = win32process.STARTUPINFO()
    try:
        win32process.CreateProcess(
            None,  # No module name (use command line)
            cmd_line,  # Command line
            None,  # Process handle not inheritable
            None,  # Thread handle not inheritable
            False,  # Set handle inheritance to FALSE
            creation_flags,  # Creation flags
            None,  # Use parent's environment block
            work_dir,  # starting directory.set None if using parent's starting directory
            startup_info,  # Pointer to STARTUPINFO structure
        )

    except Exception as e:
        _log_err(f"failed run {cmd_line}.\t{e}")


# 指定函数指针
runtask = _runtask_by_shellexecute


def fill_default_value(line: str) -> list:
    """
    为缺省的参数填充默认值

    Args:
        line: 一行配置字符串
    Returns:
        list: 应用程序,参数,启动延时,工作目录
    """
    args = line.split("，")

    def fill_parament():
        args.append("")

    def fill_delay():
        args.append(DEFAULT_DELAY_TIME)

    def fill_work_dir():  # exe所在目录
        ridx = args[0].rfind("\\")
        args.append(args[0][:ridx])

    actions = [fill_parament, fill_delay, fill_work_dir]
    # 格式：应用程序,参数,启动延时,工作目录
    for i in range(len(args) - 1, 3):
        actions[i]()
    args[2] = int(args[2])  # 时间改成整数
    return args


def _log_err(msg: str):
    with open("log.txt", mode="a", encoding="utf-8") as f:
        f.write(f"At {datetime.now().strftime('%Y/%m/%d')}:\t{msg}\n")


def _filter_running_progs(program_pool):
    """
    过滤掉已经正在运行的应用
    program_pool:[(exe, parament, delay, work_dir),...]
    """
    program_running = [p.name() for p in psutil.process_iter() if p.name() != ""]
    program_pool_ = []
    for p in program_pool:
        running = False
        for name in program_running:
            if p[0].endswith(name):
                running = True
                print(f"skip: {name}(already run)")
                break
        if not running:
            program_pool_.append(p)
    return program_pool_


def startup(groups: List[str] = ["Basic"]):
    """
    启动程序列表包含若干个程序组，使用groups参数指明启动哪些程序组。不指定的情况下，启动'Basic'程序组
    """
    run_cnt = 0
    program_pool = []  # 缓存需要执行的程序的运行参数，exe, parament, delay, work_dir
    with open("startuplist.txt", encoding="UTF-8") as f:
        for line in f.readlines():
            match line[0]:
                case "#":  # '#'开头
                    continue
                case "\n":  # 空行
                    continue
                case "@":  # 程序组的标志
                    need_run = line[1:-1] in groups
                    if need_run:
                        run_cnt += 1
                        if run_cnt > len(groups):
                            return
                    continue
            if need_run:
                args = fill_default_value(line[:-1])  # exe, parament, delay, work_dir
                program_pool.append(args)
    program_pool = _filter_running_progs(program_pool)
    for exe, parament, delay, work_dir in program_pool:
        time.sleep(delay)
        runtask(exe, parament, work_dir)


if __name__ == "__main__":
    try:
        print(sys.argv)
        if is_ac_power():
            if len(sys.argv) > 1:
                groups = sys.argv[1:]
            else:
                groups = ["Basic"]
            startup(groups)
    except Exception as e:
        print(e)
        _log_err(e)

    time.sleep(5)
